home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / telnet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  8.7 KB  |  454 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "socket.h"
  5. #include "telnet.h"
  6. #include "session.h"
  7. #include "proc.h"
  8. #include "tty.h"
  9. #include "commands.h"
  10. #include "netuser.h"
  11. #include "config.h"
  12.  
  13. #define    CTLZ    26
  14. #undef    DEBUG    1
  15.  
  16. int Refuse_echo = 0;
  17. int Tn_cr_mode = 0;    /* if true turn <cr> to <cr-nul> */
  18.  
  19. #ifdef    DEBUG
  20. char *T_options[] = {
  21.     "Transmit Binary",
  22.     "Echo",
  23.     "",
  24.     "Suppress Go Ahead",
  25.     "",
  26.     "Status",
  27.     "Timing Mark"
  28. };
  29. #endif
  30.  
  31. #ifdef    MAILBOX || CHATNODE
  32. /* Execute BBS command */
  33. int dobbschat(argc,argv,p)
  34. int argc;
  35. char *argv[];
  36. void *p;
  37. {
  38.     struct session *sp;
  39.     struct sockaddr_in fsocket;
  40.  
  41.     /* Allocate a session descriptor */
  42.     if((sp = newsession(
  43.             strncmp(argv[0],"c",1)
  44.              ? "Local BBS" : "Local ChatNode",
  45.             TELNET)) == NULLSESSION){
  46.         tprintf("Too many sessions\n");
  47.         return 1;
  48.     }
  49.     fsocket.sin_family = AF_INET;
  50.     if(argc < 3)
  51.         fsocket.sin_port = strncmp(argv[0],"c",1)
  52.              ? IPPORT_TELNET : IPPORT_CHATNODE;
  53.     else
  54.         fsocket.sin_port = atoi(argv[2]);
  55.  
  56.     if((fsocket.sin_addr.s_addr = Ip_addr) == 0){
  57.         tprintf(Badhost,sp->name);
  58.         keywait(NULLCHAR,1);
  59.         freesession(sp);
  60.         return 1;
  61.     }
  62.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  63.         tprintf("Can't create socket\n");
  64.         keywait(NULLCHAR,1);
  65.         freesession(sp);
  66.         return 1;
  67.     }
  68.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  69. }
  70. #endif
  71.  
  72. /* Execute user telnet command */
  73. int dotelnet(argc,argv,p)
  74. int argc;
  75. char *argv[];
  76. void *p;
  77. {
  78.     struct session *sp;
  79.     struct sockaddr_in fsocket;
  80.  
  81.     /* Allocate a session descriptor */
  82.     if((sp = newsession(argv[1],TELNET)) == NULLSESSION){
  83.         tprintf("Too many sessions\n");
  84.         freeargs(argc,argv);
  85.         return 1;
  86.     }
  87.     fsocket.sin_family = AF_INET;
  88.     if(argc < 3)
  89.         fsocket.sin_port = strncmp(argv[0]+1,"t",1)
  90.              ? IPPORT_TELNET : IPPORT_TTYLINK;
  91.     else
  92.         fsocket.sin_port = atoi(argv[2]);
  93.  
  94.     freeargs(argc,argv);
  95.     tprintf("Resolving %s... ",sp->name);
  96.     if((fsocket.sin_addr.s_addr = resolve(sp->name)) == 0){
  97.         tprintf(Badhost,sp->name);
  98.         keywait(NULLCHAR,1);
  99.         freesession(sp);
  100.         return 1;
  101.     }
  102.     if((sp->s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  103.         tprintf("Can't create socket\n");
  104.         keywait(NULLCHAR,1);
  105.         freesession(sp);
  106.         return 1;
  107.     }
  108.     return tel_connect(sp,(char *)&fsocket,SOCKSIZE);
  109. }
  110. /* Generic interactive connect routine, used by Telnet, AX.25, NET/ROM */
  111. int
  112. tel_connect(sp,fsocket,len)
  113. struct session *sp;
  114. char *fsocket;
  115. int len;
  116. {
  117.     unsigned int index;
  118.     struct telnet tn;
  119.  
  120.     index = sp - Sessions;
  121.     memset((char *)&tn,0,sizeof(tn));
  122.     tn.eolmode = Tn_cr_mode;
  123.     tn.session = sp;    /* Upward pointer */
  124.     sp->cb.telnet = &tn;    /* Downward pointer */
  125.  
  126.     tprintf("Trying %s...\n",psocket((struct sockaddr *)fsocket));
  127.     if(connect(sp->s,fsocket,len) == -1){
  128.           tprintf("%s session %u failed: %s errno %d\n",
  129.          Sestypes[sp->type], index, sockerr(sp->s),errno);
  130.  
  131.         keywait(NULLCHAR,1);
  132.         freesession(sp);
  133.         return 1;
  134.     }
  135.     tprintf("%s session ",Sestypes[sp->type]);
  136.     tprintf("%u connected to %s\n",index,sp->name);
  137.     tnrecv(&tn);
  138.     return 0;
  139. }
  140.  
  141. extern int EightBit;
  142.  
  143. /* Telnet input routine, common to both telnet and ttylink */
  144. void
  145. tnrecv(tn)
  146. struct telnet *tn;
  147. {
  148.     int c,s,index;
  149.     struct session *sp;
  150.     char *cp;
  151.  
  152.     sp = tn->session;
  153.     s = sp->s;
  154.  
  155.     /* We run both the network and local sockets in transparent mode
  156.      * because we have to do our own eol mapping
  157.      */
  158.     seteol(s,"");
  159.     seteol(Curproc->input,"");
  160.     seteol(Curproc->output,"");
  161.  
  162.     /* Read real keystrokes from the keyboard */
  163.     sp->ttystate.crnl = 0;
  164.  
  165.     /* Make sure network output gets flushed appropriately */
  166.     switch(sp->type){
  167.     case AX25TNC:
  168.     case NRSESSION:
  169.         setflush(s,'\r');
  170.         break;
  171.     case TELNET:
  172.         setflush(s,'\n');
  173.         break;
  174.     }
  175.  
  176.     index = sp - Sessions;
  177.  
  178.     /* Fork off the transmit process */
  179.     sp->proc1 = newproc("tel_out",1024,tel_output,0,tn,NULL);
  180.  
  181.     /* Process input on the connection */
  182.     while((c = recvchar(s)) != -1){
  183.         if(c != IAC){
  184.             /* Ordinary character */
  185.             if(!EightBit)
  186.             if(!tn->remote[TN_TRANSMIT_BINARY])
  187.                 c &= 0x7f;
  188.  
  189.             tputc((char)c);
  190.             /* AX25 and NET/ROM sessions map cr to cr/nl on input */
  191.             if(c == '\r' && (sp->type == AX25TNC || sp->type == NRSESSION))
  192.                 tputc('\n');
  193.             continue;
  194.         }
  195.         /* IAC received, get command sequence */
  196.         c = recvchar(s);
  197.         switch(c){
  198.         case WILL:
  199.             willopt(tn,recvchar(s));
  200.             break;
  201.         case WONT:
  202.             wontopt(tn,recvchar(s));
  203.             break;
  204.         case DO:
  205.             doopt(tn,recvchar(s));
  206.             break;
  207.         case DONT:
  208.             dontopt(tn,recvchar(s));
  209.             break;
  210.         case IAC:    /* Escaped IAC */
  211.             tputc(IAC);
  212.             break;
  213.         }
  214.     }
  215. quit:    /* A close was received from the remote host.
  216.      * Notify the user, kill the output task and wait for a response
  217.      * from the user before freeing the session.
  218.      */
  219.     cp = sockerr(s);
  220.     tprintf("%s session %u", Sestypes[sp->type],index);
  221.     tprintf(" closed: %s\n", cp != NULLCHAR ? cp : "EOF");
  222.     killproc(sp->proc1);
  223.     sp->proc1 = NULLPROC;
  224.     close_s(sp->s);
  225.     sp->s = -1;
  226.     keywait(NULLCHAR,1);
  227.     freesession(sp);
  228. }
  229.  
  230. /* User telnet output task, started by user telnet command */
  231. void
  232. tel_output(unused,tn1,p)
  233. int unused;
  234. void *tn1;
  235. void *p;
  236. {
  237.     struct session *sp;
  238.     int c;
  239.     struct telnet *tn;
  240.  
  241.     tn = (struct telnet *)tn1;
  242.     sp = tn->session;
  243.  
  244.     /* Send whatever's typed on the terminal */
  245.     while((c = recvchar(sp->input)) != EOF){
  246.         usputc(sp->s,(char)c);
  247.         /* Standard telnet calls for cr to map to cr/lf on output.
  248.          * The optional mode maps to cr-nul.
  249.          */
  250.         if(c == '\r' && sp->type == TELNET){
  251.             if(tn->eolmode == 0)
  252.                 usputc(sp->s,'\n');
  253.             else
  254.                 usputc(sp->s,'\0');
  255.         }
  256.         if(tn->remote[TN_ECHO])
  257.             usflush(sp->s);
  258.     }
  259.     /* Make sure our parent doesn't try to kill us after we exit */
  260.     sp->proc1 = NULLPROC;
  261. }
  262. int
  263. doecho(argc,argv,p)
  264. int argc;
  265. char *argv[];
  266. void *p;
  267. {
  268.     if(argc < 2){
  269.         if(Refuse_echo)
  270.             tprintf("Refuse\n");
  271.         else
  272.             tprintf("Accept\n");
  273.     } else {
  274.         if(argv[1][0] == 'r')
  275.             Refuse_echo = 1;
  276.         else if(argv[1][0] == 'a')
  277.             Refuse_echo = 0;
  278.         else
  279.             return -1;
  280.     }
  281.     return 0;
  282. }
  283. /* set for unix end of line for remote echo mode telnet */
  284. int
  285. doeol(argc,argv,p)
  286. int argc;
  287. char *argv[];
  288. void *p;
  289. {
  290.     if(argc < 2){
  291.         if(Tn_cr_mode)
  292.             tprintf("null\n");
  293.         else
  294.             tprintf("standard\n");
  295.     } else {
  296.         if(argv[1][0] == 'n')
  297.             Tn_cr_mode = 1;
  298.         else if(argv[1][0] == 's')
  299.             Tn_cr_mode = 0;
  300.         else {
  301.             tprintf("Usage: %s [standard|null]\n",argv[0]);
  302.             return -1;
  303.         }
  304.     }
  305.     return 0;
  306. }
  307.  
  308. /* The guts of the actual Telnet protocol: negotiating options */
  309. void
  310. willopt(tn,opt)
  311. struct telnet *tn;
  312. int opt;
  313. {
  314.     int ack;
  315.  
  316. #ifdef    DEBUG
  317.     printf("recv: will ");
  318.     if(uchar(opt) <= NOPTIONS)
  319.         printf("%s\n",T_options[opt]);
  320.     else
  321.         printf("%u\n",opt);
  322. #endif
  323.     
  324.     switch(uchar(opt)){
  325.     case TN_TRANSMIT_BINARY:
  326.     case TN_ECHO:
  327.     case TN_SUPPRESS_GA:
  328.         if(tn->remote[uchar(opt)] == 1)
  329.             return;        /* Already set, ignore to prevent loop */
  330.         if(uchar(opt) == TN_ECHO){
  331.             if(Refuse_echo){
  332.                 /* User doesn't want to accept */
  333.                 ack = DONT;
  334.                 break;
  335.             } else {
  336.                 /* Put tty into raw mode */
  337.                 tn->session->ttystate.echo = 0;
  338.                 tn->session->ttystate.edit = 0;
  339.             }
  340.         }
  341.         tn->remote[uchar(opt)] = 1;
  342.         ack = DO;            
  343.         break;
  344.     default:
  345.         ack = DONT;    /* We don't know what he's offering; refuse */
  346.     }
  347.     answer(tn,ack,opt);
  348. }
  349. void
  350. wontopt(tn,opt)
  351. struct telnet *tn;
  352. int opt;
  353. {
  354. #ifdef    DEBUG
  355.     printf("recv: wont ");
  356.     if(uchar(opt) <= NOPTIONS)
  357.         printf("%s\n",T_options[uchar(opt)]);
  358.     else
  359.         printf("%u\n",uchar(opt));
  360. #endif
  361.     if(uchar(opt) <= NOPTIONS){
  362.         if(tn->remote[uchar(opt)] == 0)
  363.             return;        /* Already clear, ignore to prevent loop */
  364.         tn->remote[uchar(opt)] = 0;
  365.         if(uchar(opt) == TN_ECHO){
  366.             /* Put tty into cooked mode */
  367.             tn->session->ttystate.echo = 1;
  368.             tn->session->ttystate.edit = 1;
  369.         }
  370.     }
  371.     answer(tn,DONT,opt);    /* Must always accept */
  372. }
  373. void
  374. doopt(tn,opt)
  375. struct telnet *tn;
  376. int opt;
  377. {
  378.     int ack;
  379.  
  380. #ifdef    DEBUG
  381.     printf("recv: do ");
  382.     if(uchar(opt) <= NOPTIONS)
  383.         printf("%s\n",T_options[uchar(opt)]);
  384.     else
  385.         printf("%u\n",uchar(opt));
  386. #endif
  387.     switch(uchar(opt)){
  388. #ifdef    FUTURE    /* Use when local options are implemented */
  389.         if(tn->local[uchar(opt)] == 1)
  390.             return;        /* Already set, ignore to prevent loop */
  391.         tn->local[uchar(opt)] = 1;
  392.         ack = WILL;
  393.         break;
  394. #endif
  395.     default:
  396.         ack = WONT;    /* Don't know what it is */
  397.     }
  398.     answer(tn,ack,opt);
  399. }
  400. void
  401. dontopt(tn,opt)
  402. struct telnet *tn;
  403. int opt;
  404. {
  405. #ifdef    DEBUG
  406.     printf("recv: dont ");
  407.     if(uchar(opt) <= NOPTIONS)
  408.         printf("%s\n",T_options[uchar(opt)]);
  409.     else
  410.         printf("%u\n",uchar(opt));
  411. #endif
  412.     if(uchar(opt) <= NOPTIONS){
  413.         if(tn->local[uchar(opt)] == 0){
  414.             /* Already clear, ignore to prevent loop */
  415.             return;
  416.         }
  417.         tn->local[uchar(opt)] = 0;
  418.     }
  419.     answer(tn,WONT,opt);
  420. }
  421. void
  422. answer(tn,r1,r2)
  423. struct telnet *tn;
  424. int r1,r2;
  425. {
  426.     char s[3];
  427.  
  428. #ifdef    DEBUG
  429.     switch(r1){
  430.     case WILL:
  431.         printf("sent: will ");
  432.         break;
  433.     case WONT:
  434.         printf("sent: wont ");
  435.         break;
  436.     case DO:
  437.         printf("sent: do ");
  438.         break;
  439.     case DONT:
  440.         printf("sent: dont ");
  441.         break;
  442.     }
  443.     if(r2 <= 6)
  444.         printf("%s\n",T_options[r2]);
  445.     else
  446.         printf("%u\n",r2);
  447. #endif
  448.  
  449.     s[0] = IAC;
  450.     s[1] = r1;
  451.     s[2] = r2;
  452.     send(tn->session->s,s,3,0);
  453. }
  454.